package org.crud4j.ejb3;

import java.lang.reflect.Method;

import java.util.Map;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Transient;

import static org.apache.commons.beanutils.PropertyUtils.*;
import org.crud4j.core.CrudBeanDef;
import org.crud4j.core.CrudFieldDef;
import org.crud4j.core.defprovider.CrudBeanDefProvider;

/**
 * Definition provider that reads JPA annotations to update the crud bean
 * definition
 */
public class Ejb3CrudBeanDefProvider implements CrudBeanDefProvider
{

    /**
     * Updates the crud bean definition according to jpa annotations
     */
    public void updateDef(Class type, CrudBeanDef crudBeanDef)
    {
        try
        {
            Object bean = type.newInstance();
            Map<String, Object> properties = describe(bean);
            properties.remove("class");
            for (String key : properties.keySet())
            {
                // FIXME check other methods ?
                Method m = getPropertyDescriptor(bean, key).getReadMethod();
                // field Name
                CrudFieldDef fieldDef = crudBeanDef.getFieldDef(key);
                if (fieldDef == null)
                {
                    continue;
                }
                // transient annotation
                if (m.isAnnotationPresent(Transient.class))
                {
                    fieldDef.setEditDisabled(true);
                    fieldDef.setNewDisabled(true);
                }

                // Id annotation
                if (m.isAnnotationPresent(Id.class))
                {
                    fieldDef.setId(true);
                    fieldDef.setNullable(false);
                }

                // generated value annotation
                if (m.isAnnotationPresent(GeneratedValue.class))
                {
                    fieldDef.setEditDisabled(true);
                    fieldDef.setNewDisabled(true);
                    fieldDef.setGeneratedValue(true);
                }

                // Column annotation
                if (m.isAnnotationPresent(Column.class))
                {
                    Column c = m.getAnnotation(Column.class);

                    fieldDef.setNullable(c.nullable());
                    fieldDef.setEditDisabled(!c.updatable());
                    fieldDef.setNewDisabled(!c.insertable());

                    if (c.length() > 0)
                    {
                        fieldDef.setLength(c.length());
                    }
                }

                // Join column annotation
                if (m.isAnnotationPresent(JoinColumn.class))
                {
                    JoinColumn c = m.getAnnotation(JoinColumn.class);
                    fieldDef.setNullable(c.nullable());
                }

            }
        } catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }
}
